package com.zzh.lib.core.lang.span;


import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.text.style.ReplacementSpan;

import androidx.annotation.ColorInt;

import com.zzh.lib.core.lang.HStrUtils;
import com.zzh.lib.core.utils.HResUtils;
import com.zzh.lib.core.utils.LogUtils;

/**
 * Created by zzh on 2024/9/6.
 *
 * @date: 2024/9/6 15:40
 * @email: zzh_hz@126.com
 * @author: zzh
 * @description: com.zzh.lib.core.lang.style
 * 〈带背景色的圆角span〉
 */
public class TextShapeSpan extends ReplacementSpan {

    private float mSize, strokeWidth = 2, textSize = -1;
    private int mBgColor;
    private int mTxtColor, strokeColor;
    private int mRadius;

    public static final int STYLE_FILL = 0;//填充
    public static final int STYLE_STROKE = 1;//扫边。扫边颜色默认和字体颜色一致
    private int mStyle = STYLE_FILL;
    private int backgroundResource;
    private Drawable backgroundDrawable;


    private float paddingStart = 0, paddingTop, paddingEnd = 0, paddingBottom;
    private float marginStart = 0, marginTop, marginEnd = 0, marginBottom;
    private Paint.Align textAlign = Paint.Align.CENTER;


    /**
     * @param radius 圆角半径
     */
    public TextShapeSpan(int bgColor, int strokeColor, int txtColor, int radius, int style) {
        mBgColor = bgColor;
        this.strokeColor = strokeColor;
        mTxtColor = txtColor;
        mRadius = radius;
        mStyle = style;
    }

    public TextShapeSpan(int textSize, int strokeWidth, int bgColor, int strokeColor, int txtColor, int radius, int style) {
        mBgColor = bgColor;
        this.strokeWidth = strokeWidth;
        this.textSize = textSize;
        this.strokeColor = strokeColor;
        mTxtColor = txtColor;
        mRadius = radius;
        mStyle = style;
    }

    public TextShapeSpan(int strokeWidth, int bgColor, int strokeColor, int txtColor, int radius, int style) {
        mBgColor = bgColor;
        this.strokeWidth = strokeWidth;
        this.strokeColor = strokeColor;
        mTxtColor = txtColor;
        mRadius = radius;
        mStyle = style;
    }


    @Override
    public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
        //paint.setTextSize(paint.getTextSize());
        setPaintTextSize(paint);
        mSize = (int) (paint.measureText(text, start, end)) + paddingStart + paddingEnd + marginStart + marginEnd + strokeWidth * 2;
        //mSize就是span的宽度，span有多宽，开发者可以在这里随便定义规则
        //我的规则：这里text传入的是SpannableString，start，end对应setSpan方法相关参数
        //可以根据传入起始截至位置获得截取文字的宽度，最后加上左右两个圆角的半径得到span宽度
        return (int) mSize;
    }

    @Override
    public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) {
        paint.setAntiAlias(true);
        paint.setTextAlign(textAlign);
        setPaintTextSize(paint);
        setPaintTextSize(paint);
        if (getDrawable() == null) {
            if (mStyle == STYLE_STROKE) {
                paint.setColor(getStrokeColor());
                paint.setStyle(Paint.Style.STROKE);
                paint.setStrokeWidth(strokeWidth);
            } else {
                strokeWidth = 0;
                paint.setColor(mBgColor);
                paint.setStyle(Paint.Style.FILL);
                paint.setStrokeWidth(0);
            }

            RectF oval = new RectF(x + marginStart, top + marginTop, x + mSize - marginEnd + paddingEnd, bottom - marginBottom);
            if (oval.height() < textSize) {
                oval.bottom = bottom + (textSize - oval.height()) / 2;
            }
            //x.y均为原字符串文字的参数
            //设置背景矩形，x为文字左边缘的x值，y为文字的baseline的y值。paint.ascent()获得baseline到文字上边缘的值，paint.descent()获得baseline到文字下边缘
            canvas.drawRoundRect(oval, mRadius, mRadius, paint);//绘制圆角矩形，第二个参数是x半径，第三个参数是y半径
            //文字 -- 绘制的文字要比原文字小 , 默认小 4sp
            drawText(canvas, text, start, end, x, top, y, bottom, paint, oval);
            //绘制文字
        } else {
            RectF rect = createRect(x + marginStart, y, paint);
            drawBackground(canvas, text, start, end, x, top, y, bottom, paint, rect);
            //String tag = HStrUtils.substring(text.toString(), start, end);
            drawText(canvas, text, start, end, x, top, y, bottom, paint, rect);
        }
    }

    protected void drawText(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint, RectF rect) {
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(getTxtColor());
        paint.setTextAlign(textAlign);
        Paint.FontMetricsInt tagFontMetrics = paint.getFontMetricsInt();
        float textX = x + rect.width() / 2 + marginStart;


        float baseline = rect.bottom - rect.height() / 2 + (float) (tagFontMetrics.bottom - tagFontMetrics.top) / 2 - tagFontMetrics.bottom;
        canvas.drawText(text, start, end, textX, baseline, paint);
    }

    protected void drawBackground(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint, RectF rect) {
        if (getDrawable() == null) {
            return;
        }

        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.FILL);
        getDrawable().setBounds((int) rect.left, (int) rect.top, (int) rect.right, (int) rect.bottom);
        getDrawable().draw(canvas);
    }

    protected RectF createRect(float x, int y, Paint paint) {
        Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt();
        final float strokeWidth = paint.getStrokeWidth();
        float left = x + strokeWidth /*+ marginStart*/;
        float top = y + fontMetrics.ascent - paddingTop;
        float right = x + mSize + strokeWidth * 2 + marginStart - marginEnd - paddingEnd;
        float bottom = y + fontMetrics.descent + paddingBottom;
        return new RectF(left, top, right, bottom);
    }

    public int getStrokeColor() {
        if (strokeColor == 0) {
            return mTxtColor;
        }
        return strokeColor;
    }

    public void setStrokeColor(int strokeColor) {
        this.strokeColor = strokeColor;
    }

    public int getRadius() {
        return mRadius;
    }

    public float getStrokeWidth() {
        return strokeWidth;
    }

    public TextShapeSpan setStrokeWidth(float strokeWidth) {
        this.strokeWidth = strokeWidth;
        return this;
    }

    public TextShapeSpan setRadius(int mRadius) {
        this.mRadius = mRadius;
        return this;
    }

    public int getTxtColor() {
        return mTxtColor;
    }

    public TextShapeSpan setTxtColor(int mTxtColor) {
        this.mTxtColor = mTxtColor;
        return this;
    }

    public int getBgColor() {
        return mBgColor;
    }

    public TextShapeSpan setBgColor(int mBgColor) {
        this.mBgColor = mBgColor;
        return this;
    }

    public int getStyle() {
        return mStyle;
    }

    public TextShapeSpan setStyle(int mStyle) {
        this.mStyle = mStyle;
        return this;
    }

    public TextShapeSpan() {
    }


    public TextShapeSpan setBackgroundResource(int resid) {

        this.mBgColor = 0;
        if (resid != 0 && resid == backgroundResource) {
            return this;
        }

        Drawable d = null;
        if (resid != 0) {
            d = HResUtils.getDrawable(resid);
        }
        setBackgroundDrawable(d);

        this.backgroundResource = resid;
        return this;
    }

    public TextShapeSpan setBackgroundDrawable(Drawable backgroundDrawable) {
        if (this.backgroundDrawable == backgroundDrawable) {
            return this;
        }
        this.backgroundDrawable = backgroundDrawable;
        this.backgroundResource = 0;
        this.mBgColor = 0;
        return this;
    }

    public Drawable getBackgroundDrawable() {
        return backgroundDrawable;
    }

    public TextShapeSpan setBackgroundColor(@ColorInt int backgroundColor) {
        this.mBgColor = backgroundColor;
        this.backgroundResource = 0;
        backgroundDrawable = null;

        return this;
    }

    public int getBackgroundResource() {
        return backgroundResource;
    }

    public Drawable getDrawable() {
        if (getBackgroundDrawable() == null) {
            if (backgroundResource == 0) {
                return null;
            } else {
                return HResUtils.getDrawable(backgroundResource);
            }

        }
        return getBackgroundDrawable();
    }

    public float getMarginBottom() {
        return marginBottom;
    }

    public TextShapeSpan setMarginBottom(float marginBottom) {
        this.marginBottom = marginBottom;
        return this;
    }

    public float getMarginEnd() {
        return marginEnd;
    }

    public TextShapeSpan setMarginEnd(float marginEnd) {
        this.marginEnd = marginEnd;
        return this;
    }

    public float getMarginTop() {
        return marginTop;
    }

    public TextShapeSpan setMarginTop(float marginTop) {
        this.marginTop = marginTop;
        return this;
    }

    public float getMarginStart() {
        return marginStart;
    }

    public TextShapeSpan setMarginStart(float marginStart) {
        this.marginStart = marginStart;
        return this;
    }

    public float getPaddingBottom() {
        return paddingBottom;
    }

    public TextShapeSpan setPaddingBottom(float paddingBottom) {
        this.paddingBottom = paddingBottom;
        return this;
    }

    public float getPaddingEnd() {
        return paddingEnd;
    }

    public TextShapeSpan setPaddingEnd(float paddingEnd) {
        this.paddingEnd = paddingEnd;
        return this;
    }

    public float getPaddingTop() {
        return paddingTop;
    }

    public TextShapeSpan setPaddingTop(float paddingTop) {
        this.paddingTop = paddingTop;
        return this;
    }

    public float getPaddingStart() {
        return paddingStart;
    }

    public TextShapeSpan setPaddingStart(float paddingStart) {
        this.paddingStart = paddingStart;
        return this;
    }

    public TextShapeSpan setPadding(float start, float top, float end, float bottom) {
        setPaddingStart(start).setPaddingTop(top).setPaddingEnd(end).setPaddingBottom(bottom);
        return this;
    }

    public TextShapeSpan setMargin(float start, float top, float end, float bottom) {
        setMarginStart(start).setMarginTop(top).setMarginEnd(end).setMarginBottom(bottom);
        return this;
    }

    public float getTextSize() {
        return textSize;
    }

    public void setTextSize(float textSize) {
        this.textSize = textSize;
    }

    public void setPaintTextSize(Paint paint) {
        if (textSize >= 0 && paint != null) {
            paint.setTextSize(textSize);
        }
    }

}

